using System;
using System.Collections;
using System.Threading;
using SecuBat.Work;
using Css.Diagnostics;
using SecuBat.Logging;

namespace SecuBat.Threading
{
	/// <summary>
	/// Summary description for QueueController.
	/// </summary>
	public class QueueController : IDisposable
	{
		private Timer _theTimer;
		private WorkQueue _queue;
		private ThreadControllerCollection _threadControllers;
		private StatusTickHandler _tickHandler;
		private bool _running;
		private String _queueName;
		private int _delayBeforeTask;

		public bool Running
		{
			get { return _running; }
		}

		public int DelayBeforeTask
		{
			get { return _delayBeforeTask; }
			set { _delayBeforeTask = value; }
		}

		public QueueController(WorkQueue queue, ThreadControllerCollection threadControllers, StatusTickHandler tickHandler, String queueName)
		{
			_queue = queue;
			_threadControllers = threadControllers;
			_tickHandler = tickHandler;
			_running = false;
			_queueName = queueName;
			_delayBeforeTask = 0;
		}

		public void Start()
		{
			// callback delegate 
			TimerCallback tcallback = new TimerCallback(this.CheckQueue) ; 

			// define the dueTime and period 
			long dTime = 100 ;  // wait before the first tick (in ms) 
			long pTime = 5 ; // timer during subsequent invocations (in ms) 

			// instantiate the Timer object 
			_theTimer = new Timer(tcallback, null, dTime, pTime);
			_running = true;

			LogManager.Write(TraceLevel.Verbose, this._queueName + " queue controller was started.", "Threading");
		}

		public void Stop()
		{
			if (_theTimer != null)
			{
				_theTimer.Dispose();
				_theTimer = null;
			}
			_running = false;
			LogManager.Write(TraceLevel.Verbose, this._queueName + " queue controller was stopped.", "Threading");
		}

		public void CheckQueue(Object state)
		{
			lock (_queue)
			{
				int count = _queue.Count;
				if (count > 0)
				{
					// Peek the task
					Task t = _queue.Peek();
					if (t != null)
					{
						// Try to get a new worker thread
						ThreadController controller = _threadControllers.AddController(t);
						if (controller != null)
						{
							// A worker thread has been successfully gained, so really dequeue the task
							Task t2 = _queue.Dequeue();

							// Check if the task really matches the peeked one - multithreading
							if (t2 != t)
							{
								LogManager.Write(TraceLevel.Warning, "The peeked task does not match the dequeued one, perhaps there seem to occure some multitasking problems?", "Threading");	
								((WorkerThread) controller.ControlledThread).WorkingTask = t2;
							}

							// Delay the task if needed
							if (this.DelayBeforeTask > 0)
							{
								LogManager.Write(TraceLevel.Information, "Delaying execution of task for " + this.DelayBeforeTask + " ms.", "Threading");
								Thread.Sleep(this.DelayBeforeTask);
							}

							// Start the worker thread
							controller.SetListener(_tickHandler);
							LogManager.Write(TraceLevel.Verbose, _queueName + " working queue: " + count + " tasks, started new worker thread " + controller.ControlledThread.GetHashCode() + ".", "Threading");
							controller.Start();
						}
					}
				}
			}
		}
		
		#region IDisposable Members

		public void Dispose()
		{
			_theTimer.Dispose();
		}

		#endregion
	}
}
